// 字符串扩展
if (String)
{
    /**
     * 扩展字符串驼峰转连接符
     * */
    if (!String.prototype.camelCaseToHyphen)
    {
        String.prototype.camelCaseToHyphen = function(): string
        {
            return this ? this.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase() : "";
        };

        // 不可枚举以及不可重写
        Object.defineProperty(String.prototype, "camelCaseToHyphen", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展字符串连接符转驼峰
     * */
    if (!String.prototype.upperCamelCase)
    {
        String.prototype.upperCamelCase = function(): string
        {
            const re = /-(\w)/g;

            return this ? this.replace(re, function(_, $1)
            {
                return $1.toUpperCase();
            }) : "";
        };

        // 不可枚举以及不可重写
        Object.defineProperty(String.prototype, "upperCamelCase", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展字符串原型的迭代函数
     * @param {function} callFn 返回为false，则为需要终止迭代
     * */
    if (!String.prototype.each)
    {
        String.prototype.each = function(callFn: (item: string, index: number) => void | boolean): void
        {
            if (callFn)
            {
                const _this = this;

                const arrayLength = _this.length;

                for (let i = 0; i < arrayLength; i++)
                {
                    const item: string = _this[i];

                    const fn = callFn.call(_this, item, i);

                    if (fn === false)
                    {
                        break;
                    }
                }
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(String.prototype, "each", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 返回该字符串的一部分，从指定的索引开始，然后扩展到给定数量的字符
     * @param {number} index 指定的位置游标
     * @param {number} length 需要裁剪的长度
     * */
    if (!String.prototype.substr)
    {
        String.prototype.substr = function(index: number, length = 0): string
        {
            if (index < 0)
            {
                index = this.length + index;
            }

            if (length <= 0)
            {
                length = this.length + length;
            }

            if (index > length)
            {
                [index, length] = [length, index];
            }

            if (this.substring)
            {
                return this.substring(index, length);
            }
            else
            {
                let subStr = "";

                this.each((value: string, thisIndex: number) =>
                {
                    if (thisIndex >= index && thisIndex < length)
                    {
                        subStr += value;
                    }
                });

                return subStr;
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(String.prototype, "substr", {
            enumerable: false,
            writable: false
        });
    }
}

// 数组扩展
if (Array)
{
    /**
     * 扩展数组原型的删除元素方法（函数式）
     * @param {function} callFn 返回为true，则为需要删除的元素
     * */
    if (!Array.prototype.remove)
    {
        Array.prototype.remove = function <T>(callFn: (item: T, index: number) => boolean): T[]
        {
            if (callFn)
            {
                const _this = this;

                _this.forEach((item: T, index: number) =>
                {
                    const fn = callFn.call(_this, item, index);

                    if (fn)
                    {
                        _this.splice(index, 1);
                    }
                });
            }

            // 返回当前对象，以便链式调用
            return this;
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "remove", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组原型的删除元素方法（方法式）
     * @param {string | number} data 删除的元素索引或值
     * @param {string} type 当参数值为value时，删除是按照值删除，当参数值为index时，删除是按照索引删除, 默认按照索引删除
     * */
    if (!Array.prototype.removeData)
    {
        Array.prototype.removeData = function <T>(data: string | number, type?: string): T[]
        {
            const _this = this;

            type = type || "index";

            let itemIndex: number | null = null;

            // 删除值
            if (type === "value")
            {
                itemIndex = _this.indexOf(data);

                if (itemIndex >= 0)
                {
                    _this.splice(itemIndex, 1);
                }
            }
            // 删除索引
            else if (type === "index")
            {
                if (isString(data))
                {
                    const thisData = data as string;

                    if (!isNaN(Number(thisData)))
                    {
                        itemIndex = Number(thisData);
                    }
                    else
                    {
                        throw new Error("需要正确的删除索引");
                    }
                }
                else if (isNumber(data))
                {
                    itemIndex = data as number;
                }

                // 当前索引长度
                const length = _this.length;

                if (itemIndex != null && itemIndex <= length - 1)
                {
                    _this.splice(itemIndex, 1);
                }
            }

            // 返回当前对象，以便链式调用
            return this;
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "removeData", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组原型删除数组重复项
     * */
    if (!Array.prototype.removeDuplicates)
    {
        Array.prototype.removeDuplicates = function <T>(): T[]
        {
            // 返回当前对象，以便链式调用
            return [
                ...new Set(this)
            ];
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "removeDuplicates", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组原型过滤数组中无效的值（虚假值）
     * */
    if (!Array.prototype.removeFalsy)
    {
        Array.prototype.removeFalsy = function <T>(): T[]
        {
            // 返回当前对象，以便链式调用
            return this.filter(Boolean);
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "removeFalsy", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组原型获取数组中参数的平均值
     * */
    if (!Array.prototype.average)
    {
        Array.prototype.average = function(): number
        {
            return this.reduce((a: number, b: number) => a + b);
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "average", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组原型获取数组中参数的最大值
     * */
    if (!Array.prototype.max)
    {
        Array.prototype.max = function(): number
        {
            return Math.max.apply(null, this);
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "max", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组原型的迭代函数
     * @param {function} callFn 返回为false，则为需要终止迭代
     * */
    if (!Array.prototype.each)
    {
        Array.prototype.each = function <T>(callFn: (item: T, index: number) => void | boolean): void
        {
            if (callFn)
            {
                const _this = this;

                const arrayLength = _this.length;

                for (let i = 0; i < arrayLength; i++)
                {
                    const item: T = _this[i];

                    const fn = callFn.call(_this, item, i);

                    if (fn === false)
                    {
                        break;
                    }
                }
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "each", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组指定元素的位置
     * @param {number} beforeIndex 调整前的索引位置
     * @param {number} afterIndex 调整后的索引位置
     * */
    if (!Array.prototype.adjustSort)
    {
        Array.prototype.adjustSort = function <T>(beforeIndex: number, afterIndex: number): T[]
        {
            if (this.length)
            {
                if (beforeIndex === afterIndex)
                {
                    return this;
                }
                else
                {
                    const exchangeTemplate = this[beforeIndex];

                    this[beforeIndex] = this[afterIndex];

                    this[afterIndex] = exchangeTemplate;

                    return this;
                }
            }
            else
            {
                return this;
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "adjustSort", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组的扁平化功能
     * */
    if (!Array.prototype.flat)
    {
        Array.prototype.flat = function <T>(): T[]
        {
            if (this.length)
            {
                const arrList = JSON.parse(JSON.stringify(this));

                const result: T[] = [];

                while (arrList.length)
                {
                    // 弹出堆栈中的数据
                    const arr = arrList.shift();

                    if (Array.isArray(arr))
                    {
                        arrList.unshift(...arr);
                    }
                    else
                    {
                        result.push(arr);
                    }
                }

                return result;
            }
            else
            {
                return this;
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "flat", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组元素位置移动
     * */
    if (!Array.prototype.move)
    {
        Array.prototype.move = function <T>(from: number, to: number): T[]
        {
            if (this.length)
            {
                const [moved] = this.splice(from, 1);

                this.splice(to, 0, moved);

                return this;
            }
            else
            {
                return this;
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "move", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数组在自定索引位置插入数据
     * */
    if (!Array.prototype.insert)
    {
        Array.prototype.insert = function <T>(data: T, index: number): T[]
        {
            // 如果插入的索引大于了数组长度,那么在最后一位插入
            if (index > this.length)
            {
                this.push(data);
            }
            else
            {
                this.splice(index, 0, data);
            }

            // 返回当前对象，以便链式调用
            return this;
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Array.prototype, "insert", {
            enumerable: false,
            writable: false
        });
    }

    // if (!Array.prototype.intersperse)
    // {
    //    Object.defineProperty(Array.prototype, 'intersperse', {
    //        enumerable: false,
    //        writable: false,
    //        configurable: false,
    //        value: function intersperse<T>(this: T[], mkT: (ix: number) => T): T[]
    //        {
    //            return this.reduce((acc: T[], d, ix) => [...acc, mkT(ix), d], []).slice(1);
    //        }
    //    });
    // }
}

// 数字扩展
if (Number)
{
    /**
     * 扩展数字原型的迭代函数
     * @param {function} callFn 返回为false，则为需要终止迭代
     * */
    if (!Number.prototype.each)
    {
        Number.prototype.each = function(callFn: (item: number) => void | boolean): void
        {
            if (callFn)
            {
                const _this = this;

                const thisNumber = Number(_this);

                for (let i = 0; i < thisNumber; i++)
                {
                    const fn = callFn.call(_this, i);

                    if (fn === false)
                    {
                        break;
                    }
                }
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Number.prototype, "each", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展数字原型的遍历函数
     * @param {function} callFn 返回为false, 则为需要终止遍历
     * */
    if (!Number.prototype.repeat)
    {
        Number.prototype.repeat = function(callFn: (item: number) => void | boolean): void
        {
            if (callFn)
            {
                const _this = this;

                const thisNumber = Number(_this);

                for (let i = 0; i < thisNumber; i++)
                {
                    const fn = callFn.call(_this, i);

                    if (fn === false)
                    {
                        break;
                    }
                }
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Number.prototype, "repeat", {
            enumerable: false,
            writable: false
        });
    }
}

// 对象扩展
if (Object)
{
    /**
     * 扩展对象原型的迭代函数
     * @param {function} callFn 返回为false，则为需要终止迭代
     * */
    if (!Object.prototype.each)
    {
        Object.prototype.each = function <T>(callFn: (item: T, key: string) => void | boolean): void
        {
            if (callFn)
            {
                const _this = this as Record<string, any>;

                for (const key in _this)
                {
                    const item: T = _this[key.toString()];

                    const fn = callFn.call(_this, item, key);

                    if (fn === false)
                    {
                        break;
                    }
                }
            }
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Object.prototype, "each", {
            enumerable: false,
            writable: false
        });
    }

    /**
     * 扩展对象原型的hasOwn函数
     * @param {object} data 当前对象数据
     * @param {string} key 要检测的key
     * */
    if (!Object.prototype.hasOwn)
    {
        Object.prototype.hasOwn = function <T>(data: T, key: string): boolean
        {
            // return key in data;
            return Object.prototype.hasOwnProperty.call(data, key);
        };

        // 不可枚举以及不可重写
        Object.defineProperty(Object.prototype, "hasOwn", {
            enumerable: false,
            writable: false
        });
    }
}